#include "stream_muxing_base.h"
namespace Media
{


	StreamMuxingBase::StreamMuxingBase(
		const std::string& stream_type,
		AVCodecContext* in_video_codec,
		AVCodecContext* in_audio_codec)
	{
		

		auto ret = avformat_alloc_output_context2(&p_out_formatctx, NULL, stream_type.data(), NULL);
		if (ret < 0)
		{
			avformat_free_context(p_out_formatctx);
			p_out_formatctx = nullptr;
			std::cout << "HLS实例封装打包失败" << std::endl;
			return;
		}

		if (nullptr != in_video_codec)
		{
			p_in_video_codec_centext = in_video_codec;
			if (!this->addStream(in_video_codec,m_video_out_index))
			{
				Log::printError("HLS视频节目码流新增失败");
	
				avformat_free_context(p_out_formatctx);
				p_out_formatctx = nullptr;
				return;
			}
		}

		if (nullptr != in_audio_codec)
		{
			p_in_audio_codec_centext = in_audio_codec;
			if (!this->addStream(in_audio_codec,m_audio_out_index))
			{
				Log::printError("HLS音频节目码流新增失败");
	
				avformat_free_context(p_out_formatctx);
				p_out_formatctx = nullptr;
				return;
			}
		}

		// 4.注册写文件到内存
		p_out_buffer = new uint8_t[MAX_CACHE_SIZE];
		// 第三个参数异常重要 如果是对外输出这个参数一定设置成1
		auto avio_out = avio_alloc_context(p_out_buffer, MAX_CACHE_SIZE, 1, this, NULL, write2Memory, NULL);
		p_out_formatctx->pb = avio_out;



		//ret = avio_open(&p_out_formatctx->pb,"test.flv", AVIO_FLAG_WRITE);
		//if (ret < 0)
		//{
		//	//std::cout << "输出数据失败:" + out_url << std::endl;
		//	return;
		//}

		
		m_init_status = true;
	}

	bool StreamMuxingBase::start()
	{
		if (m_init_status)
		{
			if (avformat_write_header(p_out_formatctx, NULL) < 0)
			{
				m_init_status = false;
				Log::printError("封装失败");
				return false;
			}
			//Log::printInfo("输出码流");
			av_dump_format(p_out_formatctx, 0, m_stream_url.data(), 1);
			for (size_t i = 0; i < p_out_formatctx->nb_streams; i++)
			{
				// 挨个遍历流
				auto stream = p_out_formatctx->streams[i];
				switch ((int)stream->codecpar->codec_type)
				{
				case AVMEDIA_TYPE_VIDEO:
				{
					p_out_video_stream = stream;
				}; break;
				case AVMEDIA_TYPE_AUDIO: {
					p_out_audio_stream = stream;
				}; break;
				}
			}
		}
		
		return true;
	}


	int StreamMuxingBase::write2Memory(void* opaque, uint8_t* buf, int buf_size)
	{
		//std::cout << "收到数据" << buf_size <<std::endl;
		StreamMuxingBase* p_this = (StreamMuxingBase*)opaque;
		if (nullptr == p_this)
		{
			return buf_size;
		}

		p_this->streamOut2Memory(buf, buf_size);
		return buf_size;
	}

	bool StreamMuxingBase::addStream(AVCodecContext* p_in_codec, int& out_index)
	{
		if (p_in_codec != nullptr)
		{
			// 2.向里边加入一个流
			auto codec = avcodec_find_encoder(p_in_codec->codec_id);
			if (!codec) {
				Log::printError("添加码流未找到编码器");
				return false;
			}

			auto stream = avformat_new_stream(p_out_formatctx, codec);
			if (!stream) {

				Log::printError("Could not allocate stream");
				return false;
			}
			stream->time_base = p_in_codec->time_base;
			stream->id = p_out_formatctx->nb_streams - 1;
			stream->index = p_out_formatctx->nb_streams - 1;



			auto ret = avcodec_parameters_from_context(stream->codecpar, p_in_codec);
			if (ret < 0)
			{
				Log::printError("StreamMuxingBase::addStream - 拷贝视频解码器及码流信息失败");
				return false;
			}
			stream->id = p_out_formatctx->nb_streams - 1;
			stream->codecpar->codec_tag = 0;
			out_index = stream->id;
		}
		return true;
	}

	
	StreamMuxingBase::~StreamMuxingBase()
	{
		avformat_free_context(p_out_formatctx);
		p_out_formatctx = nullptr;
		if (nullptr != p_out_buffer)
		{
			delete p_out_buffer;
			p_out_buffer = nullptr;
		}
		
		
	}




}
